package com.cmc.cloud.cmclink.doc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.lock.annotation.Lock4j;
import com.cmc.cloud.cmclink.csm.api.base.dto.resp.CompanyNameCastRespDTO;
import com.cmc.cloud.cmclink.csm.api.base.enums.DataTypeEnum;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.BlnoRuleKlcodeErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.entity.BlnoRuleKlcodeDO;
import com.cmc.cloud.cmclink.doc.mapper.BlnoRuleKlcodeMapper;
import com.cmc.cloud.cmclink.doc.rpcservice.CustomerRpcService;
import com.cmc.cloud.cmclink.doc.service.BlnoRuleKlcodeService;
import com.cmc.cloud.cmclink.doc.util.so.CodesUtil;
import com.cmc.cloud.cmclink.doc.vo.blnoruleklcodevo.*;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;
import com.cmes.framework.common.pojo.PageResult;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 订舱号提单号规则 三位码 Service 实现类
 *
 * @author 招商轮船-管理员
 */
@Service
@Validated
public class BlnoRuleKlcodeServiceImpl implements BlnoRuleKlcodeService {

    @Resource
    private BlnoRuleKlcodeMapper blnoRuleKlcodeMapper;

    @Resource
    private CustomerRpcService nameTransferService;

    private final Integer num = 3;

    @Override
    @Lock4j(name = "blnoRuleKlcodeUnique", keys = {"#createReqVO.getBkpCode", "#createReqVO.getBkpBlnoCode"})
    public void createBlnoRuleKlcode(BlnoRuleKlcodeCreateReqVO createReqVO) {
        // 插入
        validateCodeExistEd(createReqVO, null);
        BlnoRuleKlcodeDO blnoRuleKlcode = BeanUtil.copyProperties(createReqVO, BlnoRuleKlcodeDO.class);
        blnoRuleKlcodeMapper.insert(blnoRuleKlcode);
    }

    @Override
    @Lock4j(name = "blnoRuleKlcodeUnique", keys = {"#updateReqVO.getBkpCode", "#updateReqVO.getBkpBlnoCode"})
    public void updateBlnoRuleKlcode(BlnoRuleKlcodeUpdateReqVO updateReqVO) {
        // 校验存在
        validateBlnoRuleKlcodeExists(updateReqVO.getId());
        validateCodeExistEd(updateReqVO, updateReqVO.getId());
        // 更新
        BlnoRuleKlcodeDO updateObj = BeanUtil.copyProperties(updateReqVO, BlnoRuleKlcodeDO.class);
        blnoRuleKlcodeMapper.updateById(updateObj);
    }

    @Override
    public void deleteBlnoRuleKlcode(Long id) {
        // 校验存在
        validateBlnoRuleKlcodeExists(id);
        // 删除
        blnoRuleKlcodeMapper.deleteById(id);
    }

    private void validateBlnoRuleKlcodeExists(Long id) {
        if (blnoRuleKlcodeMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(BlnoRuleKlcodeErrorCodeConstants.BLNO_RULE_KLCODE_NOT_EXISTS);
        }
    }

    private void validateCodeExistEd(BlnoRuleKlcodeBaseVO vo, Long id) {
        LambdaQueryWrapperX<BlnoRuleKlcodeDO> queryWrapperX = new LambdaQueryWrapperX<BlnoRuleKlcodeDO>()
                .eqIfPresent(BlnoRuleKlcodeDO::getBkpCode, vo.getBkpCode());
        if (id != null) {
            queryWrapperX.ne(BlnoRuleKlcodeDO::getId, id);
        }
        if (blnoRuleKlcodeMapper.selectCount(queryWrapperX) != 0L) {
            throw ServiceExceptionUtil.exception(BlnoRuleKlcodeErrorCodeConstants.BLNO_RULE_BKPCODE_EXISTED);
        }
        LambdaQueryWrapperX<BlnoRuleKlcodeDO> queryWrapperX1 = new LambdaQueryWrapperX<BlnoRuleKlcodeDO>()
                .eqIfPresent(BlnoRuleKlcodeDO::getBkpBlnoCode, vo.getBkpBlnoCode());
        if (id != null) {
            queryWrapperX1.ne(BlnoRuleKlcodeDO::getId, id);
        }
        if (blnoRuleKlcodeMapper.selectCount(queryWrapperX1) != 0L) {
            throw ServiceExceptionUtil.exception(BlnoRuleKlcodeErrorCodeConstants.BLNO_RULE_KLCODE_EXISTED);
        }
    }

    @Override
    public BlnoRuleKlcodeDO getBlnoRuleKlcode(Long id) {
        return blnoRuleKlcodeMapper.selectById(id);
    }

    @Override
    public List<BlnoRuleKlcodeDO> getBlnoRuleKlcodeList(Collection<Long> ids) {
        return blnoRuleKlcodeMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<BlnoRuleKlcodeRespVO> getBlnoRuleKlcodePage(BlnoRuleKlcodePageReqVO reqVO) {
        LambdaQueryWrapperX<BlnoRuleKlcodeDO> queryWrapperX = new LambdaQueryWrapperX<BlnoRuleKlcodeDO>();
        if (StringUtils.isNotEmpty(reqVO.getKeyWord())) {
            queryWrapperX.like(BlnoRuleKlcodeDO::getBkpBlnoCode, reqVO.getKeyWord()).or()
                    .like(BlnoRuleKlcodeDO::getBkpCode, reqVO.getKeyWord());
            List<String> strings = nameTransferService.addQuery(reqVO.getKeyWord(), DataTypeEnum.CUSTOMER);
            if (CollectionUtil.isNotEmpty(strings)) {
                queryWrapperX.or().in(BlnoRuleKlcodeDO::getBkpCode, strings);
            }
        }
        PageResult<BlnoRuleKlcodeDO> pageResult = blnoRuleKlcodeMapper.selectPage(reqVO, queryWrapperX);
        List<BlnoRuleKlcodeRespVO> voList = BeanUtil.copyToList(pageResult.getList(), BlnoRuleKlcodeRespVO.class);
        if (CollectionUtil.isNotEmpty(voList)) {
            nameTransferService.fillName(voList);
        }
        return new PageResult<>(voList, pageResult.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> findRuleByBkpCodeAndCreate(List<String> bkpCodes, boolean needCreate) {
        Map<String, String> resultMap = new HashMap<>(16);
        if (CollectionUtil.isEmpty(bkpCodes)) {
            return resultMap;
        }
        bkpCodes = bkpCodes.stream().distinct().collect(Collectors.toList());
        LambdaQueryWrapperX<BlnoRuleKlcodeDO> queryWrapperX = new LambdaQueryWrapperX<BlnoRuleKlcodeDO>();
        queryWrapperX.in(BlnoRuleKlcodeDO::getBkpCode, bkpCodes);
        List<BlnoRuleKlcodeDO> list = blnoRuleKlcodeMapper.selectList(queryWrapperX);
        resultMap = list.stream().filter(e -> e.getEnable() == true).collect(Collectors.toMap(BlnoRuleKlcodeDO::getBkpCode, BlnoRuleKlcodeDO::getBkpBlnoCode));
        if (needCreate == false) {
            return resultMap;
        }
        // 订舱管理-CMCLINK 选择了订舱人 CSMcode 提交 SO 的时候如果这个 CSMcode 还没有三位码。系统自动给分配三位码。
        if (bkpCodes.size() == list.size()) {
            return resultMap;
        }
        //开始新增 第一位1-9A-Z  没有设置过的数据
        List<String> haveList = list.stream().map(e -> e.getBkpCode()).collect(Collectors.toList());
        List<String> noMatchBkpCodeList = bkpCodes.stream().filter(e -> haveList.contains(e) == false).collect(Collectors.toList());
        Set<String> newBkpBlnoCodeSet = new HashSet<>();
        for (int i = 0; i < noMatchBkpCodeList.size() * num; i++) {
            newBkpBlnoCodeSet.addAll(getMoreCodes(noMatchBkpCodeList.size()));
            if (newBkpBlnoCodeSet.size() > noMatchBkpCodeList.size()) {
                break;
            }
        }
        List<String> newBkpBlnoCodeList = newBkpBlnoCodeSet.stream().collect(Collectors.toList());
        if (newBkpBlnoCodeList.size() < noMatchBkpCodeList.size()) {
            throw ServiceExceptionUtil.exception(BlnoRuleKlcodeErrorCodeConstants.BLNO_RULE_BKPCODE_CREATE_ERROR);
        }
        Map<String, CompanyNameCastRespDTO> newCompanyList = nameTransferService.getCompanyMap(noMatchBkpCodeList);
        List<BlnoRuleKlcodeDO> newBlnoRuleKlcodeList = new ArrayList<>();
        List<String> errorList = new ArrayList<>();
        for (int i = 0; i < noMatchBkpCodeList.size(); i++) {
            BlnoRuleKlcodeDO newBlno = new BlnoRuleKlcodeDO();
            CompanyNameCastRespDTO company = newCompanyList.get(noMatchBkpCodeList.get(i));
            if (company == null) {
                errorList.add(noMatchBkpCodeList.get(i));
                continue;
            }
            newBlno.setBkpCode(noMatchBkpCodeList.get(i));
            newBlno.setBkpBlnoCode(newBkpBlnoCodeList.get(i));
            newBlno.setEnable(true);
            newBlnoRuleKlcodeList.add(newBlno);
            resultMap.put(newBlno.getBkpCode(), newBlno.getBkpBlnoCode());
        }
        // 判断是否有异常数据
        if (CollectionUtil.isNotEmpty(errorList)) {
            throw ServiceExceptionUtil.exception(BlnoRuleKlcodeErrorCodeConstants.BLNO_RULE_BKPCODE_NO_MATCH_ERROR, StringUtils.join(errorList, ","));
        }
        blnoRuleKlcodeMapper.insertBatch(newBlnoRuleKlcodeList);
        return resultMap;
    }

    public List<String> getMoreCodes(int noMatchBkpCodeSize) {
        //超量生成多个Code
        List<String> newBkpBlnoCodeList = CodesUtil.doGenerate(noMatchBkpCodeSize * 10, 3);
        LambdaQueryWrapperX<BlnoRuleKlcodeDO> queryWrapper = new LambdaQueryWrapperX<BlnoRuleKlcodeDO>();
        queryWrapper.in(BlnoRuleKlcodeDO::getBkpBlnoCode, newBkpBlnoCodeList);
        List<BlnoRuleKlcodeDO> checklist = blnoRuleKlcodeMapper.selectList(queryWrapper);
        List<String> checkCodelist = checklist.stream().map(e -> e.getBkpBlnoCode()).collect(Collectors.toList());
        //数据库过滤
        return newBkpBlnoCodeList.stream().filter(e -> checkCodelist.contains(e) == false).collect(Collectors.toList());
    }

}
